#ifndef __LOGGER_H_DEFINE
#define __LOGGER_H_DEFINE
#include <unistd.h>
#include <iostream>
#include <stdint.h>
#include <memory>
#include <list>
#include <sstream>
#include <fstream>
#include <vector>
#include <forward_list>

namespace sylar{

class LogLevel{
public:
    enum Level{
        UNKNOW = 0,
        DEBUG = 1,
        INFO = 2,
        WARN = 3,
        ERROR = 4,
        FATAL = 5
    };
    inline static std::string ToString(Level level){
        switch (level)
        {
        #define XX(name) \
        case LogLevel::Level::name:\
            return #name;\
            break;
        XX(DEBUG);
        XX(INFO);
        XX(WARN);
        XX(ERROR);
        XX(FATAL);
        #undef XX
        
        default:
            return "UNKNOW";
        }
        return "UNKNOW";
    }
};


class LogEvent{
public:
    typedef std::shared_ptr<LogEvent> smart_ptr;
    LogEvent(LogLevel::Level levle, const char* file, int32_t line, int32_t threadId, int32_t fiberId, int64_t time, std::string& content);
    virtual ~LogEvent() = default;
    
    const char* get_filename(){return m_file;}
    int32_t get_line() const{return m_line;}
    int32_t get_threadId() const{return m_threadId;}
    int32_t get_fiberId() const{return m_fiberId;}
    int64_t get_time() const{return m_time;}
    const std::string* get_content(){return &m_content;}
    LogLevel::Level get_level(){return m_level;}
    std::string get_logger(){return m_logger_name;}

    void set_loggerName(std::string& name){m_logger_name = name;}
    void set_level(LogLevel::Level level){m_level = level;}
private:
    const char* m_file = nullptr;   // file name
    int32_t m_line = 0;             // line number
    uint32_t m_threadId = 0;        // thread id
    uint32_t m_fiberId = 0;         // coroutine id
    uint64_t m_time;                // timestamp since program start
    std::string m_content;          // string to output
    LogLevel::Level m_level;
    std::string m_logger_name;
};

class FormatItem{
public:
    typedef std::shared_ptr<FormatItem> smart_ptr;
    FormatItem()= default;;
    ~FormatItem()= default;;
    virtual void format(std::stringstream& ss, LogEvent::smart_ptr event){};
private:
        
};

class LogFormatter{
public:
    typedef std::shared_ptr<LogFormatter> smart_ptr;
    explicit LogFormatter(const std::string& format);
    virtual ~LogFormatter()= default;;
    std::string format(LogEvent::smart_ptr event);
private:
    std::string m_pattern;
    std::list<FormatItem::smart_ptr> m_items;
};


class LogAppender{
public:
    typedef std::shared_ptr<LogAppender> smart_ptr;
    explicit LogAppender(LogFormatter::smart_ptr formatter);
    LogAppender(): m_level(LogLevel::INFO){};
    virtual ~LogAppender() = default;
    virtual void log(LogLevel::Level level, LogEvent::smart_ptr event) = 0;
    void setFormatter(LogFormatter::smart_ptr formatter){m_formatter = formatter;};
protected:
    LogLevel::Level m_level;
    LogFormatter::smart_ptr m_formatter;
};


class Logger{
public:
    typedef std::shared_ptr<Logger> smart_ptr;
    explicit Logger(const std::string& name="root");
    virtual ~Logger()= default;;
    
    void log(LogLevel::Level level, LogEvent::smart_ptr event);
    
    void debug(LogEvent::smart_ptr event);
    void info(LogEvent::smart_ptr event);
    void warn(LogEvent::smart_ptr event);
    void error(LogEvent::smart_ptr event);
    void fatal(LogEvent::smart_ptr event);

    void addAppender(LogAppender::smart_ptr appender);
    void deleteAppender(LogAppender::smart_ptr appender);


private:
    std::string m_name;             //name of logger
    LogLevel::Level m_level;    
    std::list<LogAppender::smart_ptr> m_appenders;    //appender list
};


class StdoutLogAppender : public LogAppender{
public:
    typedef std::shared_ptr<StdoutLogAppender> smart_ptr;
    virtual void log(LogLevel::Level level, LogEvent::smart_ptr event) override;
private:

};

class FileLogAppender : public LogAppender{
public:
    explicit FileLogAppender(const std::string& filename);
    typedef std::shared_ptr<FileLogAppender> smart_ptr;
    void log(LogLevel::Level level, LogEvent::smart_ptr event) override;
    virtual bool reopen();
private:
    std::string m_filename;
    std::ofstream m_filestream;
};

};










#endif // __LOGGER_H_DEFINE
